package ch.sv7.tool.dbmanager.db.utils;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import ch.sv7.tool.dbmanager.db.Identifiable;
import ch.sv7.tool.dbmanager.db.TableSchema;
import ch.sv7.tool.dbmanager.db.difference.AbstractTableDifference;
import ch.sv7.tool.dbmanager.db.difference.SchemaDifferences;

/**
 *
 * @author svt
 *
 */
public class CompareTool {

	public static void compareList(SchemaDifferences differences, 
			TableSchema actualTableSchema, 
			TableSchema expectedTableSchema,  
			List/*<Identifiable>*/ expected,
			List/*<Identifiable>*/ actual,
			Class missingDifference,
			Class extraDifference){
		if (expected == null || actual == null) {
			throw new IllegalArgumentException();
		}
		List expectedList = new ArrayList(expected);
		List actualList = new ArrayList(actual);
		
		Iterator expectedIter = expectedList.iterator();
		while (expectedIter.hasNext()) {
			Identifiable expectedItem = (Identifiable)expectedIter.next();
			Identifiable actualItem = find(actualList, expectedItem);			
			if (actualItem != null) {
				expectedItem.computeDifferencesFromActual(differences, actualItem);
				expectedIter.remove();
				actualList.remove(actualItem);
			} else {
				AbstractTableDifference diff = buildDifference(actualTableSchema, expectedTableSchema, expectedItem, missingDifference);
				if (diff != null){
					differences.addDifference(expectedTableSchema, diff);
				}
				expectedIter.remove();
			}
		}
		
		for (int i=0; i< actualList.size(); i++) {
			Identifiable i1 = (Identifiable)actualList.get(i);
			Identifiable i2 = find(expectedList, i1);
			if (i2 == null) {
				AbstractTableDifference diff = buildDifference(actualTableSchema, expectedTableSchema, i1, extraDifference);
				if (diff != null){
					differences.addDifference(expectedTableSchema, diff);
				}
			}				
		}		
		
	}
	
	public static AbstractTableDifference buildDifference(TableSchema actualTableSchema, TableSchema expectedTableSchema, Object elt, Class differenceClass){
		try {
			Constructor constructor = differenceClass.getConstructor(new Class[]{TableSchema.class, TableSchema.class, elt.getClass()});
			AbstractTableDifference diff = (AbstractTableDifference)constructor.newInstance(new Object[]{expectedTableSchema, actualTableSchema, elt});
			return diff;
		} catch (Exception e) {
			return null;
		}
	}
	
	public static Identifiable find(List/*<Identifiable>*/ list, Identifiable item){
		if (list == null || list.size() == 0){
			return null;
		} else {
			for (int i=0; i<list.size(); i++) {
				Identifiable elt = (Identifiable)list.get(i);
				if (elt.getIdentity().equals(item.getIdentity()) &&
						elt.getEntityType().equals(item.getEntityType())){
					return elt;
				}
			}
			return null;
		}
	}
}
